home *** CD-ROM | disk | FTP | other *** search
- /*
- C* -- Register allocation code.
-
- source: reg.c
- started: August 4, 1986
- version:
- February 20, 1986
- March 7, 1989
-
- PUBLIC DOMAIN SOFTWARE
-
- The CSTAR program was placed in the public domain on June 15, 1991,
- by its author and sole owner,
-
- Edward K. Ream
- 1617 Monroe Street
- Madison, WI 53711
- (608) 257-0802
-
- CSTAR may be used for any commercial or non-commercial purpose.
-
- See cstar.h or cstar.c for a DISCLAIMER OF WARRANTIES.
- */
- #include "cstar.h"
-
- /*
- NOTE: For the time being, get_temp creates fresh nodes
- every time. Nodes have to be held through the completion of
- the peephole phase, and it is NOT, repeat NOT, ok to change
- them simply because gen_xxx has already been called on them!
- */
-
- /*
- AVAIL registers are not defined by the user or used as special regs.
- FREE registers are registers which may be used as temporaries.
- USED registers have been used since the last regs_init
- such registers need to be saved and restored by the function.
- */
-
- /* Forward declarations of functions. */
- static struct node * get_bot();
- static int get_free();
-
- /* -----
- #enum(1, GET_A, GET_D, GET_S)
- ----- */
- #define GET_A 1
- #define GET_D 2
- #define GET_S 3
-
- /* Define S stack, a simulation stack used to allocate registers. */
- #define SS_MAX 200
- extern int ss_count, ss_forks, ss_bot;
-
- static struct node * s_stack[SS_MAX];
- static int sf_stack[SS_MAX];
-
- /* Track the AVAILABLE registers, and which of them are FREE. */
- static int ga_avail [8];
- static int gd_avail [8];
-
- extern int sa_avail [8];
- extern int sd_avail [8];
-
- extern int sa_used [8];
- extern int sd_used [8];
-
- static int sa_free [8];
- static int sd_free [8];
-
-
- /* Keep track of the number of registers in each set. */
- static int na_avail;
- static int nd_avail;
-
- extern int na_free;
- extern int nd_free;
-
- /*
- Externally visible routines:
- */
- void regs_clear (void);
- unsigned long pd_alloc (struct type_node *t, int mode);
- struct node * locn_xconst (long value);
- struct node * locn_dupl (struct node *s);
- struct node * locn_xdupl (struct node *s);
- struct node * locn_chmod (struct node *loc, int mode);
- struct node * locn_reg (int reg);
- static int get_free (int sx_free[]);
- struct node * get_temp (struct node * loc);
- struct node * get_dtemp (void);
- struct node * get_atemp (void);
- void free_temp (struct node *loc);
- void free_xtemp (struct node *loc1, struct node *loc2);
- void force_free (int reg);
- void push_scratch (void);
- void free_reg (int reg);
- bool alloc_reg (int reg);
- void regs_init (void);
- void free_all (void);
- bool is_equiv (struct node *loc1, struct node *loc2);
- bool is_cloc (struct node * loc);
- struct node * fix_cloc (register struct node * loc);
- bool is_zloc (struct node * loc);
- bool is_xloc (struct node * loc);
- bool is_xtloc (struct node * loc);
- bool is_aloc (struct node * loc);
- bool is_atloc (struct node * loc);
- bool is_atreg (int reg);
- bool is_dtreg (int reg);
- bool is_dloc (struct node * loc);
- bool is_dtloc (struct node * loc);
- bool has_dtreg (struct node * loc);
- bool has_atreg (struct node * loc);
- bool is_storloc (struct node *p);
- void ss_push (struct node * loc);
- struct node * ss_pop (void);
- struct node * ss_restore (void);
-
- /*
- Internal routines:
- */
- static int decl_reg (struct st_node *id);
- static struct node * get_bot (int reg_type, int arg);
- static struct node ** find_rloc (register int reg);
-
- /*
- Deallocate the local registers
- */
- void
- regs_clear(void)
- {
- register int i;
-
- TICK("regs_clear");
-
- na_free = nd_free = 0;
- for (i = 0; i < 8; i++) {
- if (ga_avail[i]) {
- na_avail++;
- }
- sa_avail[i] = sa_free[i] = ga_avail[i];
- if (gd_avail[i]) {
- nd_avail++;
- }
- sd_avail[i] = sd_free[i] = gd_avail[i];
- sa_used[i] = sd_used[i] = FALSE;
- }
- na_free = na_avail;
- nd_free = nd_avail;
- /* NOTE: for this purpose, A6 and A7 do not show up as sa_used;
- they are saved and restored independently of other regs */
- }
-
- /*
- Go through an ELEMENT list and do the offsets.
-
- See note in lint.c about folded variables. Offsets are treated as
- signed longs, and that may not be good enough for fully-stuffed
- or virtual memory systems.
- */
- unsigned long
- pd_alloc(struct type_node *t, int mode)
- {
- register struct type_node *t1;
- register struct st_node *id;
- register struct node *loc1, *loc3;
- register long o, size;
- register int reg;
-
- TRACEPB("pd_alloc", printf("(%p, %d)\n", t, mode));
-
- switch (mode) {
- case 0:
- /* formals */
- o = 8;
- break;
-
- case 1:
- /* locals */
- o = 0;
- break;
-
- default:
- /* all else */
- o = 0;
- }
- size = o;
-
- while (t != NULL) {
- TRACEP("pd_alloc", printf("doing node %p\n", t));
-
- if (!is_element(t -> t_typtok)) {
- t_error("pd_alloc: internal: not ELEMENT");
- break;
- }
- id = t -> t_parent;
- if (id == NULL) {
- /* currently, pure tags have no parents */
- t = t -> t_list;
- continue;
- }
- t1 = t -> t_link;
- if (t1 == NULL) {
- t_error("pd_alloc: internal: typeless ELEMENT");
- break;
- }
- switch (mode) {
- case 0:
- /* formals */
- if (t1 -> t_tsize == 1) {
- /*
- byte size argument treated as
- interchangeable with int for
- compatibility
- */
- id -> st_offset = o + 1;
- o += 2;
- }
- else {
- /* word or long size argument */
- id -> st_offset = o;
- o += (long) t1 -> t_tsize;
- }
- #ifdef DEBUG
- if (t1 -> t_tsize == 3 || t1 -> t_tsize > 4) {
- t_error("formal has bad size");
- }
- #endif /* DEBUG */
-
- if (id -> st_sclass == FORMREG_CLASS) {
- if (reg = decl_reg(id)) {
- TRACEP("pd_alloc", printf("formal register\n"););
- loc3 = locn_reg(reg);
- loc3 -> n_cltype = id -> st_type;
- loc1 = locn_xconst(id -> st_offset);
- loc1 -> n_reg1 = R_A6;
- loc1 -> n_mode = EA_MODE;
- g_2l2(X_MOVE, loc1, loc3);
- }
- else {
- id -> st_sclass = FORMAL_CLASS;
- }
- }
- break;
- case 1:
- /* locals */
- switch (id -> st_sclass) {
- case REGISTER_CLASS:
- if (decl_reg(id)) {
- id -> st_offset = 0;
- break;
- }
- else {
- id -> st_sclass = AUTO_CLASS;
- }
- /* FALL_THROUGH */
-
- case AUTO_CLASS:
- o -= (long) t1 -> t_tsize;
- /* keep start of larger objects on even boundary */
- if ((o & 1) && t1 -> t_tsize > 1) {
- o--;
- }
- id -> st_offset = o;
- break;
- }
- break;
- case 2:
- /* elements of structures */
- /* keep start of larger objects on even boundary */
- if ((o & 1) && t1 -> t_tsize > 1) {
- if (t1 -> t_typtok == ARRAY_TYPE &&
- t1 -> t_tsize == t1 -> t_tdim) {
- /* don't mess with boundary for
- array of bytes */
- }
- else {
- o++;
- }
- }
- id -> st_offset = o;
- o += (long) t1 -> t_tsize;
- break;
- case 3:
- /* elements of unions */
- id -> st_offset = 0;
-
- /* WARNING: see note above about variables without sign: */
- if (t1 -> t_tsize > (unsigned long) o) {
- o = t1 -> t_tsize;
- }
- break;
- }
- t = t -> t_list;
- }
- size -= o; /* this is the change in o */
-
- /* WARNING: see note above about variables without sign: */
- if (size < 0) {
- size = -size;
- }
-
- /* WARNING: see note above about variables without sign: */
- if (size > 1 && (size & 1)) {
- size += 1; /* effect: treat all non-characters as being
- of even size; this way something like
- byte *p; p = p + sizeof(aggregate);
- will work properly */
- }
- RETURN_ULONG("pd_alloc", (unsigned long) size);
- }
-
- /*
- mark register unavailable and assign to st_node if necessary
- */
- static int
- decl_reg(struct st_node *id)
- {
- register int i, j, reg;
-
- reg = id -> st_misc & ST_REG; /* pick up manifest reg */
-
- TRACEPB("decl_reg", printf("reg = %d\n", reg));
-
- if (is_areg(reg)) {
- /* Seize a specific A register--even a scratch register */
- i = reg_idx(reg);
- sa_free[i] = sa_avail[i] = FALSE;
- sa_used[i] = TRUE;
- TRACEP("decl_reg", printf("take manifest %s\n", arp_tab[reg]));
- if (i < A_ALLOC) {
- t_2help(arp_tab[reg], " is a scratch register");
- }
- RETURN_INT("decl_reg", reg);
- }
- else if (is_dreg(reg)) {
- /* Seize a specific D register. */
- i = reg_idx(reg);
- sd_free[i] = sd_avail[i] = FALSE;
- sd_used[i] = TRUE;
- TRACEP("decl_reg", printf("take manifest %s\n", arp_tab[reg]));
- if (i < D_ALLOC) {
- t_2help(arp_tab[reg], " is a scratch register");
- }
- RETURN_INT("decl_reg", reg);
- }
-
- if (id -> st_type -> t_typtok == INT_TYPE) {
- /* Seize any D register among D2..D7 */
- for (j = 7; j >= D_ALLOC; j--) {
- if (sd_avail[j]) {
- id -> st_misc |= d_reg(j) & ST_REG;
- sd_avail[j] = FALSE;
- sd_used[j] = TRUE;
- TRACEP("decl_reg", printf("allocate reg %s\n",
- arp_tab[d_reg(j)]));
- RETURN_INT("decl_reg", d_reg(j));
- }
- }
- }
- else {
- /* Seize any A register among A2..A5 */
- for (j = 5; j >= A_ALLOC; j--) {
- if (sa_avail[j]) {
- id -> st_misc |= a_reg(j) & ST_REG;
- sa_avail[j] = FALSE;
- sa_used[j] = TRUE;
- TRACEP("decl_reg", printf("allocate %s\n",
- arp_tab[a_reg(j)]));
- RETURN_INT("decl_reg", a_reg(j));
- }
- }
- }
- RETURN_INT("decl_reg", 0);
- }
-
-
-
- /*
- Return a constant node
- */
- struct node *
- locn_xconst(long value)
- {
- TRACEPB("locn_xconst", printf("(%ld)\n", value));
- RETURN_PTR("locn_xconst", new_cloc(value));
- }
-
- /*
- Make a new copy of a loc_node
- */
- struct node *
- locn_dupl(register struct node *s)
- {
- register int i;
- register struct node *r, *d;
-
- r = d = /* CAST(struct node *) */ new_pnode(sizeof(struct loc_node));
-
- TRACEPB("locn_dupl", printf("copy %p to %p\n", s, d));
-
- i = sizeof(struct loc_node)/sizeof(int);
- while (i--) {
- *((int *)d)++ = *((int *)s)++;
- }
- RETURN_PTR("locn_dupl", r);
- }
-
- /*
- Make a new copy of a loc_node if it is not marked
- */
- struct node *
- locn_xdupl(register struct node *s)
- {
- register int i;
- register struct node *r, *d;
-
- r = d = /* CAST(struct node *) */ new_pnode(sizeof(struct loc_node));
-
- TRACEPB("locn_xdupl", printf("copy %p to %p\n", s, d));
-
- i = sizeof(struct loc_node)/sizeof(int);
- while (i--) {
- *((int *)d)++ = *((int *)s)++;
- }
-
- RETURN_PTR("locn_xdupl", r);
- }
-
- /*
- Change the mode of a loc_node by swapping if possible
- Else by copying if marked
- Else directly
-
- It is presumed that the mode does need changing
- */
- struct node *
- locn_chmod(struct node *loc, int mode)
- {
- TRACEPB("locn_chmod", printf("(%p, %d)\n", loc, mode));
-
- loc = locn_dupl(loc);
- loc -> n_mode = (byte) mode;
-
- RETURN_PTR("locn_chmod", loc);
- }
-
- /*
- Return a loc_node corresponding to the given register
- field
-
- If the field corresponds to a temporary, do it by swapping
- */
- struct node *
- locn_reg(int reg)
- {
- TRACEPB("locn_reg", printf("(%d)\n", reg));
- RETURN_PTR("locn_reg", new_rloc(reg));
- }
-
- /*
- return index of free register
- THIS DOES NOT CHANGE THE FREE ARRAY
- */
- static int
- get_free(int sx_free[])
- {
- register int index;
-
- /* return lowest free register */
-
- TRACEPB("get_free", printf("(%p)\n", sx_free));
-
- for (index = 0; index <= 7; index++) {
- if (sx_free[index]) {
- RETURN_INT("get_free", index);
- }
- }
- RETURN_INT("get_free", 0);
- }
-
- /*
- Return a pointer to a temporary register compatible with loc.
- */
- struct node *
- get_temp(struct node * loc)
- {
- register struct node *p;
-
- TRACEPB("get_temp", printf("(%p)\n", loc));
-
- if (loc -> n_cltype -> t_typtok != INT_TYPE) {
- p = get_atemp();
- }
- else {
- p = get_dtemp();
- }
- p -> n_cltype = loc -> n_cltype;
-
- /* BUG FIX: */
- RETURN_PTR("get_temp", p);
- }
-
- /*
- Return a pointer to a D temporary register
- */
- struct node *
- get_dtemp(void)
- {
- struct node *p;
- int index;
-
- /* Return a free D register. */
-
- TICKB("get_dtemp");
-
- if (nd_free) {
- /* identify and take the free D register */
- index = get_free(sd_free);
- sd_free [index] = FALSE;
- nd_free--;
-
- p = new_rloc(d_reg(index));
- sd_used [index] = TRUE; /* sd_used is NOT related to sd_free */
- }
- else {
- /* Push the bottom D reg and return it. */
- p = get_bot(GET_D, 0);
- }
- TRACEP("get_dtemp",
- printf("return %p: %d , %d free\n", p, p -> n_reg1, nd_free));
-
- RETURN_PTR("get_dtemp", p);
- }
-
- /*
- Return a pointer to an A temporary
- */
- struct node *
- get_atemp(void)
- {
- register struct node *p;
- register int index;
-
- TICKB("get_atemp");
-
- if (na_free) {
- index = get_free(sa_free);
- sa_free [index] = FALSE;
- na_free--;
- p = new_rloc(a_reg(index));
- sa_used [index] = TRUE; /* sa_used is NOT related to sa_free */
- }
- else {
- /* Push the bottom A reg and return it. */
- p = get_bot(GET_A, 0);
- }
-
- TRACEP("get_atemp",
- printf("return %p: %d , %d free\n",
- p, a_reg(index), na_free));
-
- RETURN_PTR("get_atemp", p);
- }
-
- /*
- Get a temporary by "pushing" a stack node; at least one item is
- always "pushed".
-
- This is the only code that increases ss_bot. ss_bot is then
- decreased only by ss_pop.
-
- CAUTION: ss_bot is interrogated in g_2call and gen_args to determine
- whether anything is on the physical stack, in order to disable the
- use of nopush_loc if that is so.
-
- Nodes below ss_bot are already "pushed" in this sense. The node
- at ss_bot is examined for temporaries. If it has any, it is pushed,
- and they are freed. If either temporary is of the requested
- type, it is returned. Otherwise the process repeats with the new
- (incremented) ss_bot.
-
- If ss_bot is at or over the ss_forks threshold, nodes are resolved
- prior to being pushed. This is intended for nodes that are to
- be retrieved by ss_pop() and used directly as operands. If ss_bot
- is below the ss_forks threshold, any temporary COMPONENTS are pushed
- individually. These nodes MUST be retrieved by ss_restore(); their
- retrieval by ss_pop() is a fatal error.
-
- If a temporary is not found, a fatal error occurs.
-
- GET_S is used by push_scratch() for generating code that pushes
- all the temporaries
- */
- static struct node *
- get_bot(int reg_type, int arg)
- {
- register int reg, count;
- register struct node *loc, *loci;
-
- TRACEPB("get_bot",
- printf("(%d, %d)\n", reg_type, arg);
- printf("entry: ss_count = %d, ss_bot = %d, ss_forks = %d\n",
- ss_count, ss_bot, ss_forks));
-
- if (reg_type == GET_S) {
- count = arg;
- }
- else {
- count = ss_count;
- }
-
- while (ss_bot < count) {
- loc = s_stack[ss_bot];
-
- TRACEP("get_bot", pr_loc(loc);printf("\n"));
-
- sf_stack[ss_bot] = 0;
-
- if (ss_bot < ss_forks) {
- /* in the forks case, save node and push components */
- /* WARNING:
- if there are two components, it is not
- strictly necessary to save both of them.
- However, it simplifies the bookkeeping
- */
- if (reg = loc -> n_reg1) {
- if (is_atreg(reg) || is_dtreg(reg)) {
- /* mark r1 save */
- sf_stack[ss_bot] |= 0x801;
- loci = locn_reg(reg);
- loci -> n_cltype = long_type;
- g_2l1(X_MOVE, loci, push_loc);
- }
- if ((reg = loc -> n_reg2) &&
- (is_atreg(reg) || is_dtreg(reg))
- ) {
- /* mark r2 save */
- sf_stack[ss_bot] |= 0x802;
- loci = locn_reg(reg);
- if (loc -> n_scflag == X2_WORD) {
- loci -> n_cltype = int_type;
- }
- else {
- loci -> n_cltype = long_type;
- }
- g_2l1(X_MOVE, loci, push_loc);
- }
- free_temp(loc);
- }
- }
- else {
- /* in the normal case, combine node to value and push */
- /* caller routines will expect the value in pop_loc
- if it gets pushed */
- if (loc = x_sspush(loc)) {
- s_stack[ss_bot] = loc;
- }
- }
-
- /* return if suitable register found */
- if (reg_type == GET_A && na_free) {
- ss_bot++;
- RETURN_PTR("get_bot", get_atemp());
- }
- else if (reg_type == GET_D && nd_free) {
- ss_bot++;
- RETURN_PTR("get_bot", get_dtemp());
- }
- ss_bot++;
- }
- if (reg_type == GET_S) {
- RETURN_PTR("get_bot", NULL);
- }
- else {
- fatal("cannot get temporary");
- }
-
- TICKX("get_bot");
- }
-
-
- /*
- Find out whether any s_stack entry contains reg, regardless of
- mode
- */
- static struct node **
- find_rloc(register int reg)
- {
- register int i, count;
- register struct node **ptr, *loc;
-
- #ifdef DEBUG
- register struct node **ptr2;
- #endif
-
- TRACEPB("find_rloc", printf("(%d)\n", reg));
-
- count = ss_count;
- ptr = &s_stack[0];
- i = count;
- while (i > 0) {
- loc = *ptr;
- if (loc -> n_reg1 == reg || loc -> n_reg2 == reg) {
- break;
- }
- ptr++;
- i--;
- }
- if (i == 0) {
- RETURN_PTR("find_rloc", NULL);
- }
-
- #ifdef DEBUG
- ptr2 = ptr + 1;
- i--;
- while (i > 0) {
- if ((*ptr2) -> n_reg1 == reg || (*ptr2) -> n_reg2 == reg) {
- g_error(NULL, "duplicate instance of register in s_stack");
- }
- i--;
- ptr++;
- }
- #endif /* DEBUG */
-
- RETURN_PTR("find_rloc", ptr);
- }
-
- /*
- free registers designated in loc if they are temps
- that is, just mark them as free
- */
- void
- free_temp(register struct node *loc)
- {
- register int reg;
-
- TRACEPB("free_temp", printf("(%p)\n", loc));
-
- free_reg(loc -> n_reg1);
- free_reg(loc -> n_reg2);
-
- TICKX("free_temp");
- }
-
- /*
- free registers designated in loc1 if they are temps
- and are not in loc2
- */
- void
- free_xtemp(register struct node *loc1, register struct node *loc2)
- {
- register int reg;
-
- #ifdef DEBUG
-
- TRACEPB("free_xtemp", printf("(%p, %p)\n", loc1, loc2));
-
- if (loc2 == NULL) {
- g_error(NULL, "internal: free_xtemp: NULL exception loc");
- free_temp(loc1);
- RETURN_VOID("free_xtemp");
- }
- #endif /* DEBUG */
-
- if (reg = loc1 -> n_reg1) {
- if (reg != loc2 -> n_reg1 && reg != loc2 -> n_reg2) {
- free_reg(reg);
- }
- if (reg = loc1 -> n_reg2) {
- if (reg != loc2 -> n_reg1 && reg != loc2 -> n_reg2) {
- free_reg(reg);
- }
- }
- }
-
- TICKX("free_xtemp");
- }
-
- /*
- IF the designated register appears IN THE S_STACK, get a
- temporary of the same kind, move it to the temporary, and
- update the s_stack item appropriately. (Use locn_xdupl).
- This does NOT free the register.
- */
- void
- force_free(register int reg)
- {
- register struct node **s_loc, *loct;
- register int reg2;
-
- TRACEPB("force_free", printf("(%d)\n", reg));
-
- if (s_loc = find_rloc(reg)) {
- /* always move long; it takes the same time, and then we
- are SURE it's ok */
- /* nothing available to ss_push and donate to the pool */
- if (is_areg(reg)) {
- loct = get_atemp();
- }
- else {
- loct = get_dtemp();
- }
- loct -> n_cltype = long_type;
- g_2l2(X_MOVE, locn_reg(reg), loct);
-
- /* now alter the entry */
- *s_loc = loct = locn_xdupl(*s_loc);
- if (loct -> n_reg1 == reg) {
- loct -> n_reg1 = loct -> n_reg1;
- }
- if (loct -> n_reg2 == reg) {
- loct -> n_reg2 = loct -> n_reg1;
- }
- }
-
- TICKX("force_free");
- }
-
- /*
- going up from the bottom of the s_stack, push registers
- as if doing free_temp, until such time as the scratch regs
- are all pushed
- */
- void
- push_scratch(void)
- {
- register int ss_ptr, reg;
-
- TICKB("push_scratch");
-
- for (ss_ptr = ss_count - 1; ss_ptr >= 0; ss_ptr--) {
- reg = s_stack[ss_ptr] -> n_reg1;
- if (reg) {
- if((is_areg(reg) && reg_idx(reg) <= ASCRATCH) ||
- reg_idx(reg) <= DSCRATCH) {
- break;
- }
- reg = s_stack[ss_ptr] -> n_reg2;
- if((is_areg(reg) && reg_idx(reg) <= ASCRATCH) ||
- reg_idx(reg) <= DSCRATCH) {
- break;
- }
- }
- }
- if (ss_ptr < 0) {
- RETURN_VOID("push_scratch");
- }
- (void) get_bot(GET_S, ss_ptr + 1);
-
- TICKX("push_scratch");
- }
-
- /*
- free a register if it turns out to be a temp
- */
- void
- free_reg(register int reg)
- {
- register int i;
-
- TRACEPB("free_reg", printf("(%d)\n", reg));
-
- if (!reg) {
- RETURN_VOID("free_reg");
- }
- i = reg_idx(reg);
- if (is_areg(reg)) {
- /* Free an A register. */
- if (sa_avail[i] && !sa_free[i]) {
- sa_free[i] = TRUE;
- na_free++;
- TRACE("free_reg",
- printf("free_reg: free A reg: na_free = %d\n",
- na_free));
- }
- }
- else {
- /* Free a D register. */
- if (sd_avail[i] && !sd_free[i]) {
- sd_free[i] = TRUE;
- nd_free++;
- TRACE("free_reg",
- printf("free_reg: free D reg: nd_free = %d\n",
- nd_free));
- }
- }
-
- TICKX("free_reg");
- }
-
- /*
- allocate a specific register as a temp if it is available
- behavior is similar to get_temp, but without a search
-
- this is used, e.g. in sop_ternop
- */
- bool
- alloc_reg(register int reg)
- {
- register int i;
-
- TRACEPB("alloc_reg", printf("(%d)\n", reg));
-
- if (!reg) {
- RETURN_BOOL("alloc_reg", FALSE);
- }
- i = reg_idx(reg);
- if (is_areg(reg)) {
- /* Seize an A register. */
- if (sa_avail[i] && sa_free[i]) {
- sa_free[i] = FALSE;
- sa_used[i] = TRUE;
- na_free--;
- TRACE("alloc_reg",
- printf("alloc_reg: seize A reg: na_free = %d\n",
- na_free));
- RETURN_BOOL("alloc_reg", TRUE);
- }
- }
- else {
- /* Seize a D register. */
- if (sd_avail[i] && sd_free[i]) {
- sd_free[i] = FALSE;
- sd_used[i] = TRUE;
- nd_free--;
- TRACE("alloc_reg",
- printf("alloc_reg: seize D reg: nd_free = %d\n",
- nd_free));
- RETURN_BOOL("alloc_reg", TRUE);
- }
- }
- RETURN_BOOL("alloc_reg", FALSE);
- }
-
-
- void
- regs_init(void)
- {
- int i, na_max, nd_max;
-
- TICK("regs_init");
-
- /* WARNING: must set this up from symbol table somehow */
- na_max = 6; /* always exclude a6, a7 */
- nd_max = 8;
-
- /* set up global availabilities */
- for (i = 0; i < nd_max; i++) {
- gd_avail [i] = TRUE;
- }
- for (; i < 8; i++) {
- gd_avail [i] = TRUE;
- }
-
- for (i = 0; i < na_max; i++) {
- ga_avail [i] = TRUE;
- }
- for (; i < 6; i++) {
- ga_avail [i] = TRUE;
- }
- for (; i < 8; i++) {
- ga_avail [i] = FALSE;
- }
-
- /* set up local availabilities */
- regs_clear();
-
- /* NOTE: this better not be returned by anything since it's a push */
- a0_loc = new_grloc(R_A0);
- d0_loc = new_grloc(R_D0);
- a6_loc = new_grloc(R_A6);
- a7_loc = new_grloc(R_A7);
- sr_loc = new_grloc(R_SR);
- ccr_loc = new_grloc(R_CCR);
-
- push_loc = new_grloc(R_A7);
- push_loc -> n_mode = EAPRD_MODE;
-
- nopush_loc = new_grloc(R_A7);
- nopush_loc -> n_mode = EA_MODE;
-
- pop_loc = new_grloc(R_A7);
- pop_loc -> n_mode = EAPSI_MODE;
-
- one_loc = new_grloc(0);
- one_loc -> n_const = 1L;
-
- zero_loc = new_grloc(0);
- }
-
- /*
- Set all available regs to free and reset the pointers.
- This should normally have no effect.
- */
- void
- free_all(void)
- {
- int i;
-
- TRACEP("free_all",
- printf("free_all entry: na_free %d, nd_free %d\n",
- na_free, nd_free));
-
- na_free = nd_free = 0;
- for (i = 0; i < 8; i++) {
- /* not == */
- if (sa_free[i] = sa_avail[i]) {
- na_free++;
- }
- if (sd_free[i] = sd_avail[i]) {
- nd_free++;
- }
- }
- ss_count = ss_bot = ss_forks = 0;
- }
-
- /*
- Return TRUE if loc1 is essentially equal to loc2 so that
- either can be used in place of the other. Type is NOT
- checked and should be checked by the caller if required.
- */
- bool
- is_equiv(register struct node *loc1, register struct node *loc2)
- {
- TRACEPB("is_equiv", printf("(%p, %p)\n", loc1, loc2));
-
- if (
- loc1 -> n_mode == loc2 -> n_mode &&
- loc1 -> n_cid == loc2 -> n_cid &&
- loc1 -> n_const == loc2 -> n_const &&
- loc1 -> n_reg1 == loc2 -> n_reg1 &&
- loc1 -> n_reg2 == loc2 -> n_reg2
- ) {
- if (loc1 -> n_reg2) {
- RETURN_BOOL("is_equiv",
- (loc1 -> n_scflag == loc2 -> n_scflag));
- }
- else {
- RETURN_BOOL("is_equiv", TRUE);
- }
- }
- RETURN_BOOL("is_equiv", FALSE);
- }
-
- /*
- Return TRUE if the loc node is a constant--that is, does
- not contain a register component or EA mode.
- */
- bool
- is_cloc(struct node * loc)
- {
- TRACEPB("is_cloc", printf("(%p)\n", loc));
-
- RETURN_BOOL("is_cloc",
- loc &&
- loc -> n_mode == VALUE_MODE &&
- loc -> n_reg1 == 0);
- }
-
- /*
- If the node is not a constant, return NULL.
-
- If the node is a global constant, return NULL.
-
- If the node is or can be made into a pure numeric constant, do so.
-
- Return a conditional copy of the node.
- */
- struct node *
- fix_cloc(register struct node * loc)
- {
- register int class;
-
- TRACEPB("fix_cloc", printf("(%p)\n", loc));
-
- if (loc -> n_reg1) {
- RETURN_PTR("fix_cloc", NULL);
- }
-
- class = loc -> n_cid -> st_sclass;
- if (loc -> n_cid) {
- if ( is_rstack(class) || class == SUE_CLASS ) {
- loc = locn_xdupl(loc);
- loc -> n_const += loc -> n_cid -> st_offset;
- loc -> n_cid = NULL;
- }
- else {
- RETURN_PTR("fix_cloc", NULL);
- }
- }
- else {
- loc = locn_xdupl(loc);
- }
- RETURN_PTR("fix_cloc", loc);
- }
-
- /*
- Return TRUE if the loc node represents absolute zero.
- */
- bool
- is_zloc(struct node * loc)
- {
- TRACEPB("is_zloc", printf("(%p)\n", loc));
-
- RETURN_BOOL("is_zloc", loc &&
- loc -> n_mode == VALUE_MODE &&
- loc -> n_cid == NULL &&
- loc -> n_const == 0L &&
- loc -> n_reg1 == 0);
- }
-
- /*
- Return TRUE if the loc node represents any A or D register
- */
- bool
- is_xloc(struct node * loc)
- {
- TRACEPB("is_xloc", printf("(%p)\n", loc));
-
- RETURN_BOOL("is_xloc", loc &&
- loc -> n_cid == 0 &&
- loc -> n_mode == VALUE_MODE &&
- is_xreg(loc -> n_reg1) &&
- loc -> n_reg2 == 0);
- }
-
- /*
- Return TRUE if the loc node represents any TEMPORARY register.
- */
- bool
- is_xtloc(struct node * loc)
- {
- TRACEPB("is_xtloc", printf("(%p)\n", loc));
-
- RETURN_BOOL("is_xtloc", loc &&
- loc -> n_cid == NULL &&
- loc -> n_mode == VALUE_MODE &&
- is_xreg(loc -> n_reg1) &&
- loc -> n_reg2 == 0 &&
- (is_dreg(loc -> n_reg1) && sd_avail[reg_idx(loc -> n_reg1)] ||
- is_areg(loc -> n_reg1) && sa_avail[reg_idx(loc -> n_reg1)] ));
- }
-
- /*
- Return TRUE if the loc node represents ANY A register.
- */
- bool
- is_aloc(struct node * loc)
- {
- TRACEPB("is_aloc", printf("(%p)\n", loc));
-
- RETURN_BOOL("is_aloc", loc &&
- loc -> n_cid == NULL &&
- loc -> n_mode == VALUE_MODE &&
- is_areg(loc -> n_reg1) &&
- loc -> n_reg2 == 0);
- }
-
- /*
- Return TRUE if loc node represents any A TEMPORARY register.
- */
- bool
- is_atloc(struct node * loc)
- {
- TRACEPB("is_atloc", printf("(%p)\n", loc));
-
- RETURN_BOOL("is_atloc", loc &&
- loc -> n_cid == NULL &&
- loc -> n_mode == VALUE_MODE &&
- is_areg(loc -> n_reg1) &&
- loc -> n_reg2 == 0 &&
- sa_avail[reg_idx(loc -> n_reg1)]);
- }
-
- /*
- Return TRUE if designator designates any A TEMPORARY register.
- */
- bool
- is_atreg(int reg)
- {
- TRACEPB("is_atreg", printf("(%d)\n", reg));
-
- RETURN_BOOL("is_atreg", is_areg(reg) &&
- sa_avail[reg_idx(reg)]);
- }
-
- /*
- Return TRUE if designator designates any D TEMPORARY register.
- */
- bool
- is_dtreg(int reg)
- {
- TRACEPB("is_dtreg", printf("(%d)\n", reg));
-
- RETURN_BOOL("is_dtreg", is_dreg(reg) &&
- sd_avail[reg_idx(reg)]);
- }
-
- /*
- Return TRUE if loc node represents any D register.
- */
- bool
- is_dloc(struct node * loc)
- {
- TRACEPB("is_dloc", printf("(%p)\n", loc));
-
- RETURN_BOOL("is_dloc", loc &&
- loc -> n_cid == NULL &&
- loc -> n_mode == VALUE_MODE &&
- is_dreg(loc -> n_reg1) &&
- loc -> n_reg2 == 0);
- }
-
- /*
- Return TRUE if loc node represents any D TEMPORARY register.
- */
- bool
- is_dtloc(struct node * loc)
- {
- TRACEPB("is_dtloc", printf("(%p)\n", loc));
-
- RETURN_BOOL("is_dtloc", loc &&
- loc -> n_cid == NULL &&
- loc -> n_mode == VALUE_MODE &&
- is_dreg(loc -> n_reg1) &&
- loc -> n_reg2 == 0 &&
- sd_avail[reg_idx(loc -> n_reg1)]);
- }
-
- /*
- Return register designator if loc node contains any D TEMPORARY
- */
- int
- has_dtreg(struct node * loc)
- {
- TRACEPB("has_dtreg", printf("(%p)\n", loc));
-
- if (loc) {
- if ( is_dreg(loc -> n_reg1) &&
- sd_avail[reg_idx(loc -> n_reg1)] ) {
- TRACEP("has_dtreg", printf("reg1: %d\n", loc -> n_reg1));
- RETURN_INT("has_dtreg", loc -> n_reg1);
- }
- else if ( is_dreg(loc -> n_reg2) &&
- sd_avail[reg_idx(loc -> n_reg2)] ) {
-
- TRACEP("has_dtreg",
- printf("reg1: %d\n", loc -> n_reg1));
-
- RETURN_INT("has_dtreg", loc -> n_reg2);
- }
- }
- RETURN_INT("has_dtreg", 0);
- }
-
- /*
- Return register designator if loc node contains any D TEMPORARY
- */
- int
- has_atreg(struct node * loc)
- {
- TRACEPB("has_atreg", printf("(%p)\n", loc));
-
- if (loc) {
- if ( is_areg(loc -> n_reg1) &&
- sa_avail[reg_idx(loc -> n_reg1)] ) {
- TRACEP("has_atreg", printf("reg1: %d\n", loc -> n_reg1));
- RETURN_INT("has_atreg", loc -> n_reg1);
- }
- else if ( is_areg(loc -> n_reg2) &&
- sa_avail[reg_idx(loc -> n_reg2)] ) {
- TRACEP("has_atreg", printf("reg2: %d\n", loc -> n_reg2));
- RETURN_INT("has_atreg", loc -> n_reg2);
- }
- }
- RETURN_INT("has_atreg", 0);
- }
-
- /*
- Return TRUE if loc_node could be valid destination for move
- */
- bool
- is_storloc(struct node *p)
- {
- TRACEPB("is_storloc", printf("(%p)\n", p));
-
- if (p -> n_mode == EA_MODE) {
- RETURN_BOOL("is_storloc", TRUE);
- }
- else if (p -> n_cid || p -> n_const) {
- RETURN_BOOL("is_storloc", FALSE);
- }
- else if (p -> n_reg1 && p -> n_reg2) {
- RETURN_BOOL("is_storloc", FALSE);
- }
- RETURN_BOOL("is_storloc", TRUE);
- }
-
- /*
- Push and pop values on the S stack.
- */
- void
- ss_push(struct node * loc)
- {
- TRACEPB("ss_push",
- printf("(%p)\n", loc);
- printf("%p: ", loc);
- pr_loc(loc); printf("\n");
- printf("new ss_count %d\n", ss_count+1));
-
- if (ss_count >= SS_MAX) {
- g_error(NULL, "code generator stack overflow");
- }
- else {
- s_stack [ss_count++] = loc;
- }
-
- TICKX("ss_push");
- }
-
- /* pop a node off the s_stack for use in an expression */
- struct node *
- ss_pop(void)
- {
- TRACEPB("ss_pop",
- printf("entry: ss_count = %d, ss_bot = %d, ss_forks = %d\n",
- ss_count, ss_bot, ss_forks));
-
- if (ss_count <= 0) {
- fatal("code generator stack underflow");
- }
- else {
- TRACEP("ss_pop", printf("new ss_count %d\n", ss_count-1));
- if (--ss_count < ss_bot) {
- --ss_bot;
- #ifdef DEBUG
- if (sf_stack[ss_bot]) {
- fatal("ss_pop: internal: pops restore node");
- }
- #endif /* DEBUG */
- }
- RETURN_PTR("ss_pop", s_stack [ss_count]);
- }
-
- TICKX("ss_pop");
- }
-
- /* restore a loc_node by popping its elements off the s_stack */
- struct node *
- ss_restore(void)
- {
- register struct node *loc, *loci;
- register int flag;
-
- TRACEPB("ss_restore",
- printf("entry: ss_count = %d, ss_bot = %d, ss_forks = %d\n",
- ss_count, ss_bot, ss_forks));
-
- if (ss_bot <= 0) {
- fatal("ss_restore: underflow");
- }
-
- TRACEP("ss_restore", printf("new ss_bot %d\n", ss_bot-1));
-
- --ss_bot;
-
- loc = s_stack [ss_bot];
-
- /* restore components of node if pushed componentwise */
- flag = FALSE;
- if (sf_stack[ss_bot] & 1) {
- loci = locn_reg(loc -> n_reg1);
- loci -> n_cltype = long_type;
- g_2l2(X_MOVE, pop_loc, loci);
- (void) alloc_reg(loc -> n_reg1);
- flag = TRUE;
- }
- if (sf_stack[ss_bot] & 2) {
- loci = locn_reg(loc -> n_reg2);
- if (loci -> n_scflag == X2_WORD) {
- loci -> n_cltype = int_type;
- }
- else {
- loci -> n_cltype = long_type;
- }
- g_2l2(X_MOVE, pop_loc, loci);
- (void) alloc_reg(loc -> n_reg2);
- flag = TRUE;
- }
- sf_stack[ss_bot] = 0;
- RETURN_PTR("ss_restore", flag? loc : NULL);
- }
-